package com.example.backend.service;

import com.example.backend.annotation.LogExecution;
import com.example.backend.domain.entity.SystemLog;
import com.example.backend.domain.entity.SystemNotification;
import com.example.backend.domain.entity.SystemSetting;
import com.example.backend.domain.entity.User;
import com.example.backend.dto.SaveSettingRequest;
import com.example.backend.dto.BatchSaveSettingsRequest;
import com.example.backend.dto.NotificationTestRequest;
import com.example.backend.dto.IntegrationTestRequest;
import com.example.backend.dto.TestResultDto;
import com.example.backend.dto.SystemSettingDto;
import com.example.backend.exception.BusinessException;
import com.example.backend.repository.SystemLogRepository;
import com.example.backend.repository.SystemNotificationRepository;
import com.example.backend.repository.SystemSettingRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统设置服务
 */
@Service
@Transactional
public class SystemSettingService {
    
    private final SystemSettingRepository settingRepository;
    private final SystemLogRepository logRepository;
    private final SystemNotificationRepository notificationRepository;
    private final UserService userService;
    
    @Autowired
    public SystemSettingService(SystemSettingRepository settingRepository,
                               SystemLogRepository logRepository,
                               SystemNotificationRepository notificationRepository,
                               UserService userService) {
        this.settingRepository = settingRepository;
        this.logRepository = logRepository;
        this.notificationRepository = notificationRepository;
        this.userService = userService;
    }
    
    // ========== 系统设置管理 ==========
    
    @LogExecution("获取系统设置")
    @Cacheable(value = "system_settings", key = "#category")
    @Transactional(readOnly = true)
    public Map<String, String> getSettingsByCategory(String category) {
        List<SystemSetting> settings = settingRepository.findByCategory(category);
        return settings.stream()
                .collect(Collectors.toMap(
                    SystemSetting::getKey,
                    setting -> setting.getIsEncrypted() ? "***" : setting.getValue()
                ));
    }
    
    @LogExecution("获取单个系统设置")
    @Cacheable(value = "system_settings", key = "#category + '_' + #key")
    @Transactional(readOnly = true)
    public Optional<SystemSettingDto> getSetting(String category, String key) {
        return settingRepository.findByCategoryAndKey(category, key)
                .map(this::convertToDto);
    }
    
    @LogExecution("保存系统设置")
    @CacheEvict(value = "system_settings", allEntries = true)
    public SystemSettingDto saveSetting(String category, SaveSettingRequest request, Long userId) {
        User user = userService.findById(userId)
                .orElseThrow(() -> new BusinessException("用户不存在"));
        
        SystemSetting setting = settingRepository.findByCategoryAndKey(category, request.getKey())
                .orElse(SystemSetting.builder()
                        .category(category)
                        .key(request.getKey())
                        .build());
        
        setting.setValue(request.getValue());
        if (request.getDescription() != null) {
            setting.setDescription(request.getDescription());
        }
        setting.setUpdatedBy(user);
        
        SystemSetting saved = settingRepository.save(setting);
        
        // 记录日志
        logSettingChange("UPDATE", category, request.getKey(), saved.getValue(), user);
        
        return convertToDto(saved);
    }
    
    @LogExecution("批量保存系统设置")
    @CacheEvict(value = "system_settings", allEntries = true)
    public List<SystemSettingDto> batchSaveSettings(String category, BatchSaveSettingsRequest request, Long userId) {
        User user = userService.findById(userId)
                .orElseThrow(() -> new BusinessException("用户不存在"));
        
        List<SystemSettingDto> results = new ArrayList<>();
        
        for (Map.Entry<String, String> entry : request.getSettings().entrySet()) {
            try {
                SaveSettingRequest saveRequest = new SaveSettingRequest();
                saveRequest.setKey(entry.getKey());
                saveRequest.setValue(entry.getValue());
                saveRequest.setDescription(request.getDescription());
                
                SystemSettingDto saved = saveSetting(category, saveRequest, userId);
                results.add(saved);
            } catch (Exception e) {
                // 记录错误但继续处理其他设置
                logSettingChange("ERROR", category, entry.getKey(), entry.getValue(), user, e.getMessage());
            }
        }
        
        return results;
    }
    
    @LogExecution("获取所有设置分类")
    @Cacheable(value = "system_settings", key = "'categories'")
    @Transactional(readOnly = true)
    public List<String> getAllCategories() {
        return settingRepository.findAllCategories();
    }
    
    @LogExecution("分页获取系统设置")
    @Transactional(readOnly = true)
    public Page<SystemSettingDto> getSettings(String category, String keyword, Pageable pageable) {
        Page<SystemSetting> page = settingRepository.searchSettings(category, keyword, pageable);
        return page.map(this::convertToDto);
    }
    
    // ========== 通知测试 ==========
    
    @LogExecution("测试通知")
    public TestResultDto testNotification(NotificationTestRequest request, Long userId) {
        User user = userService.findById(userId)
                .orElseThrow(() -> new BusinessException("用户不存在"));
        
        try {
            long startTime = System.currentTimeMillis();
            
            // 根据通知类型执行不同的测试逻辑
            TestResultDto result = switch (request.getNotificationType().toUpperCase()) {
                case "EMAIL" -> testEmailNotification(request);
                case "SMS" -> testSmsNotification(request);
                case "WEBHOOK" -> testWebhookNotification(request);
                default -> new TestResultDto(false, "不支持的通知类型: " + request.getNotificationType());
            };
            
            long responseTime = System.currentTimeMillis() - startTime;
            result.setResponseTime(responseTime);
            
            // 记录测试日志
            logNotificationTest(request.getNotificationType(), request.getRecipient(), result.isSuccess(), user);
            
            return result;
            
        } catch (Exception e) {
            TestResultDto errorResult = new TestResultDto(false, "通知测试失败: " + e.getMessage());
            errorResult.setErrorDetails(e.toString());
            return errorResult;
        }
    }
    
    // ========== 集成测试 ==========
    
    @LogExecution("测试集成")
    public TestResultDto testIntegration(IntegrationTestRequest request, Long userId) {
        User user = userService.findById(userId)
                .orElseThrow(() -> new BusinessException("用户不存在"));
        
        try {
            long startTime = System.currentTimeMillis();
            
            // 根据集成类型执行不同的测试逻辑
            TestResultDto result = switch (request.getIntegrationType().toUpperCase()) {
                case "WEBHOOK" -> testWebhookIntegration(request);
                case "API" -> testApiIntegration(request);
                case "DATABASE" -> testDatabaseIntegration(request);
                default -> new TestResultDto(false, "不支持的集成类型: " + request.getIntegrationType());
            };
            
            long responseTime = System.currentTimeMillis() - startTime;
            result.setResponseTime(responseTime);
            
            // 记录测试日志
            logIntegrationTest(request.getIntegrationType(), request.getTestUrl(), result.isSuccess(), user);
            
            return result;
            
        } catch (Exception e) {
            TestResultDto errorResult = new TestResultDto(false, "集成测试失败: " + e.getMessage());
            errorResult.setErrorDetails(e.toString());
            return errorResult;
        }
    }
    
    // ========== 系统日志管理 ==========
    
    @LogExecution("获取系统日志")
    @Transactional(readOnly = true)
    public Page<SystemLog> getSystemLogs(String level, String category, String keyword, 
                                        Instant startDate, Instant endDate, Pageable pageable) {
        return logRepository.searchLogs(level, category, keyword, startDate, endDate, pageable);
    }
    
    @LogExecution("获取系统通知")
    @Transactional(readOnly = true)
    public Page<SystemNotification> getSystemNotifications(String type, Boolean isSent, String recipient, Pageable pageable) {
        if (type != null && isSent != null && recipient != null) {
            return notificationRepository.findByTypeAndIsSentAndRecipient(type, isSent, recipient, pageable);
        } else if (type != null && isSent != null) {
            return notificationRepository.findByTypeAndIsSent(type, isSent, pageable);
        } else if (type != null) {
            return notificationRepository.findByType(type, pageable);
        } else if (isSent != null) {
            return notificationRepository.findByIsSent(isSent, pageable);
        } else if (recipient != null) {
            return notificationRepository.findByRecipient(recipient, pageable);
        } else {
            return notificationRepository.findAll(pageable);
        }
    }
    
    // ========== 私有方法 ==========
    
    private SystemSettingDto convertToDto(SystemSetting setting) {
        SystemSettingDto dto = new SystemSettingDto();
        dto.setId(setting.getId());
        dto.setCategory(setting.getCategory());
        dto.setKey(setting.getKey());
        dto.setValue(setting.getIsEncrypted() ? "***" : setting.getValue());
        dto.setDescription(setting.getDescription());
        dto.setDataType(setting.getDataType());
        dto.setIsEncrypted(setting.getIsEncrypted());
        dto.setDefaultValue(setting.getDefaultValue());
        dto.setIsRequired(setting.getIsRequired());
        dto.setValidationRule(setting.getValidationRule());
        dto.setUpdatedAt(setting.getUpdatedAt());
        
        if (setting.getUpdatedBy() != null) {
            dto.setUpdatedBy(setting.getUpdatedBy().getId());
            dto.setUpdatedByName(setting.getUpdatedBy().getFullName());
        }
        
        return dto;
    }
    
    private void logSettingChange(String action, String category, String key, String value, User user) {
        logSettingChange(action, category, key, value, user, null);
    }
    
    private void logSettingChange(String action, String category, String key, String value, User user, String errorMessage) {
        SystemLog log = SystemLog.builder()
                .level("INFO")
                .category("SETTING")
                .action(action)
                .message(String.format("系统设置 %s: %s.%s", action, category, key))
                .details(errorMessage != null ? errorMessage : String.format("值: %s", value))
                .user(user)
                .build();
        
        logRepository.save(log);
    }
    
    private void logNotificationTest(String type, String recipient, Boolean success, User user) {
        SystemLog log = SystemLog.builder()
                .level(success ? "INFO" : "ERROR")
                .category("NOTIFICATION")
                .action("TEST")
                .message(String.format("通知测试 %s: %s", success ? "成功" : "失败", type))
                .details(String.format("收件人: %s", recipient))
                .user(user)
                .build();
        
        logRepository.save(log);
    }
    
    private void logIntegrationTest(String type, String url, Boolean success, User user) {
        SystemLog log = SystemLog.builder()
                .level(success ? "INFO" : "ERROR")
                .category("INTEGRATION")
                .action("TEST")
                .message(String.format("集成测试 %s: %s", success ? "成功" : "失败", type))
                .details(String.format("URL: %s", url))
                .user(user)
                .build();
        
        logRepository.save(log);
    }
    
    // ========== 测试方法实现 ==========
    
    private TestResultDto testEmailNotification(NotificationTestRequest request) {
        // 这里应该实现真实的邮件发送测试
        // 目前返回模拟结果
        return new TestResultDto(true, "邮件通知测试成功");
    }
    
    private TestResultDto testSmsNotification(NotificationTestRequest request) {
        // 这里应该实现真实的短信发送测试
        // 目前返回模拟结果
        return new TestResultDto(true, "短信通知测试成功");
    }
    
    private TestResultDto testWebhookNotification(NotificationTestRequest request) {
        // 这里应该实现真实的Webhook测试
        // 目前返回模拟结果
        return new TestResultDto(true, "Webhook通知测试成功");
    }
    
    private TestResultDto testWebhookIntegration(IntegrationTestRequest request) {
        // 这里应该实现真实的Webhook集成测试
        // 目前返回模拟结果
        return new TestResultDto(true, "Webhook集成测试成功");
    }
    
    private TestResultDto testApiIntegration(IntegrationTestRequest request) {
        // 这里应该实现真实的API集成测试
        // 目前返回模拟结果
        return new TestResultDto(true, "API集成测试成功");
    }
    
    private TestResultDto testDatabaseIntegration(IntegrationTestRequest request) {
        // 这里应该实现真实的数据库集成测试
        // 目前返回模拟结果
        return new TestResultDto(true, "数据库集成测试成功");
    }
}
